// Stephen Toub
// stoub@microsoft.com

using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Diagnostics;
using System.ComponentModel;

namespace WMVConvert.Metadata
{
	/// <summary>Metadata editor for ASF files, including WMA and WMV files.</summary>
	public sealed class Editor : EditorBase
	{
		/// <summary>IWMHeaderInfo3 interface for the editor.</summary>
		private IWMHeaderInfo3 headerInfo;
		/// <summary>Underlying metadata editor used to edit the metadata for the file.</summary>
		private IWMMetadataEditor2 editor;

		/// <summary>Initialize the editor.</summary>
		/// <param name="filepath">The path to the file whose metadata needs to be edited.</param>
		public Editor(string filepath) : this(filepath, false) {}

		private bool dirty;

		/// <summary>Initialize the editor.</summary>
		/// <param name="filepath">The path to the file whose metadata needs to be edited.</param>
		/// <param name="readOnly">Whether to open the editor read-only.</param>
		public Editor(string filepath, bool readOnly) : base(filepath)
		{
			try
			{
				editor = WMCreateEditor();
				if (readOnly)
				{
					editor.OpenEx(filepath, Constants.GENERIC_READ, Constants.FILE_SHARE_READ);
				}
				else
				{
					//editor.OpenEx(filepath, Constants.GENERIC_READ | Constants.GENERIC_WRITE, Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE | Constants.FILE_SHARE_DELETE );
					editor.Open(filepath);
				}
				headerInfo = (IWMHeaderInfo3)editor;
			}
			catch
			{
				Dispose(true);
				throw;
			}
		}

		public bool Dirty
		{
			get { return dirty; }
			internal set { this.dirty = value; }
		}

		internal IWMHeaderInfo3 HeaderInfo
		{
			get { return this.headerInfo; }
		}

		LanguageCollection languages;

		public LanguageCollection Languages
		{
			get
			{
				if (languages == null)
				{
					languages = new LanguageCollection(editor as IWMLanguageList);
				}
				return languages;
			}
		}

		public void Save()
		{
			try { editor.Flush(); }
			catch (COMException) { }
			dirty = false;
		}

		public void Close()
		{
			if (editor != null)
			{
				while (Marshal.ReleaseComObject(editor) > 0) ;
				editor = null;
			}
			if (headerInfo != null)
			{
				while (Marshal.ReleaseComObject(headerInfo) > 0) ;
				headerInfo = null;
			}
		}

		/// <summary>Releases all of the resources for the editor.</summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				Close();
			}
		}

		/// <summary>Creates a metadata editor.</summary>
		[DllImport("WMVCore.dll", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, PreserveSig=false)]
		private static extern IWMMetadataEditor2 WMCreateEditor();

		public override object this[WMAttribute key]
		{
			get
			{
				return key.Value;
			}
			set
			{
				key.Value = value;
			}
		}

		public override void Add(WMAttribute key, object value)
		{
			key.Value = value;
		}

		public override bool ContainsKey(WMAttribute key)
		{
			return key.Exist;
		}

		private WMAttributeFactory attributtes;

		public override ICollection<WMAttribute> Keys
		{
			get
			{
				throw new NotImplementedException();
				//return this.Attributes;
			}
		}

		public WMAttributeFactory Attributes
		{
			get
			{
				if (attributtes == null)
				{
					attributtes = new WMAttributeFactory(this);
				}
				return attributtes;
			}
		}

		public override bool Remove(WMAttribute key)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		public override bool TryGetValue(WMAttribute key, out object value)
		{
			value = key.Value;
			return key.Exist;
		}

		public override void Add(KeyValuePair<WMAttribute, object> item)
		{
			Add(item.Key, item.Value);
		}

		public override void Clear()
		{
			foreach (WMAttribute wmAttrib in this.Keys)
			{
				wmAttrib.DeleteValue();
			}
		}

		public override bool Contains(KeyValuePair<WMAttribute, object> item)
		{
			return ContainsKey(item.Key);
		}

		public override int Count
		{
			get
			{
				return Keys.Count;
			}
		}

		public override bool Remove(KeyValuePair<WMAttribute, object> item)
		{
			return Remove(item.Key);
		}
	}
}